package com.nextive.interview.activity;

import static com.nextive.interview.ApplicationManager.fetchService;
import static com.nextive.interview.activity.view.DefaultTextValuesHolder.fetchValueFor;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextSwitcher;
import android.widget.ToggleButton;

import com.nextive.interview.R;
import com.nextive.interview.activity.view.DefaultTextSwitcherFactory;
import com.nextive.interview.dto.ContactDetails;
import com.nextive.interview.dto.UserPreferences;
import com.nextive.interview.service.UserInfoService;
import com.nextive.interview.service.UserInfoService.Metric;
import com.nextive.interview.util.PhoneContactsUtil;
import com.nextive.interview.util.ValidationUtil;

/**
 * Activity class to manage everything related to user preferences settings.
 * <code>Please note :</code> it has been assumed that if BACK button is pressed 
 * or if the app exits for any reason, then there is <code>NO PARTIAL SAVE</code>. 
 * It is not considered a valid state to save data if confirm button has not been pressed.
 * 
 * @author Cesar Roman
 *
 */
public class SetupActivity extends Activity {
    
	/**
	 * Service to obtain user preferences.
	 */
	private UserInfoService userInfoService;
	
	// All input fields
	private EditText nameInput;
	private EditText emailInput;
	private Button confirmButton;
	private Button recipientButton;
	private TextSwitcher recipientDisplay;
	private ToggleButton metricButton;

	/**
	 * Recipient dialog to pick up a recipient's email.
	 */
	private AlertDialog recipientDialog;

	
	/**
	 * It represents phone contact details, meaning it will 
	 * contain information about a single contact chosen 
	 * from the phone's contact.
	 * Please note this is optional, it will only be valid 
	 * when the user picks up a contact.
	 */
	private ContactDetails phoneContactDetails;
	
	/**
	 * DTO object containing user preferences info.
	 */
	private UserPreferences userPreferences;
	
	/**
	 * Flag indicating if it is first time user access.
	 */
	private boolean userFirstTime = false;
	
	// Activities states
	private static final int ACTIVITY_CHOOSE = 0;
	private static final int ACTIVITY_CREATE = 1;
	
	/**
	 * Id identifying recipient dialog.
	 */
	private static final int RECIPIENT_DIALOG_ID = 0;
	
	/**
	 * This enum is used to know if we want to change settings or not.
	 */
	public enum SettingsMode {
		
		CHANGE_SETTINGS;
		
	}
	
    /**
     * It takes care of everything that has to be created or bound.
     * If it's first time the user accesses settings screen, then it 
     * configures all layouts; if not, then it just forwards to list activity.
     */
	@Override
    public void onCreate(Bundle savedInstanceState) {
    	
    	super.onCreate(savedInstanceState);
    	
    	userInfoService = fetchService(UserInfoService.class);
    	userPreferences = (UserPreferences) getLastNonConfigurationInstance();
    	if (userPreferences == null) {

    		userFirstTime = userInfoService.isUserFirstAccess();
        	if (userFirstTime || isChangeSettingsAction()) {
            	
        		configureMainLayout();
        		
            } else {
            	
            	forwardToListActivity(false);
            	
            }

    	} else {
    		
    		// the activity was destroyed/created automatically - restore data fields
    		configureMainLayout();
    		
    	}
    	
    }
    
	/**
     * When resuming, check if it is or not the first time the user accesses settings page.
     * If not, then populate settings info so user can update it.
     */
    @Override
	protected void onResume() {
		
    	super.onResume();
    	if (userPreferences == null) {

        	userPreferences = userInfoService.fetchUserInfo();
            if (userFirstTime && phoneContactDetails == null) {
            	
            	// if first time access and not coming from choose/create contacts then display welcome dialog
            	displayFirstTimeDialog();
            	updateRecipientDisplay();
            	
            }
            userFirstTime = false;

    	}
    	
    	populateSettingsInfo();
    	
	}

	/**
	 * It creates contacts dialog.
	 */
    @Override
	protected Dialog onCreateDialog(int id) {
		
		switch (id) {
		case RECIPIENT_DIALOG_ID:
			return recipientDialog;
		}
		
		return null;
	}

	/**
	 * It takes care of handling the result when choosing an existing contact or 
	 * when creating a new contact.
	 */
    @Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		
		super.onActivityResult(requestCode, resultCode, data);
		if (RESULT_OK == resultCode && (ACTIVITY_CHOOSE == requestCode || ACTIVITY_CREATE == requestCode)) {
			
			phoneContactDetails = PhoneContactsUtil.getContactDetails(data.getData());
			
		}
		
	}

    /**
     * It saves partial information so to be populated when activity comes to foreground again.
     * @return a UserPreferences
     */
    @Override
	public Object onRetainNonConfigurationInstance() {
		
		userPreferences.setName(nameInput.getText().toString());
		userPreferences.setEmail(emailInput.getText().toString());
		userPreferences.setMetricOption(metricButton.isChecked() ? Metric.KG : Metric.LB);
		userPreferences.setRecipientEmail(userPreferences.getRecipientEmail());
    	return userPreferences;
    	
	}

	/**
     * It populates all user settings. If coming back from choose/create contact, then it 
     * populates with whatever info we had already on the screen.
     */
    private void populateSettingsInfo() {
    	
    	if (phoneContactDetails != null) {
        	
        	// coming back from choose/create contact, then fill out with previous info
    		userPreferences.setRecipientEmail(phoneContactDetails.getEmail());
    		userPreferences.setName(nameInput.getText().toString());
    		userPreferences.setEmail(emailInput.getText().toString());
    		userPreferences.setMetricOption(metricButton.isChecked() ? Metric.KG : Metric.LB);
    		phoneContactDetails = null;
    		
    	}
    	
    	updateNameDisplay();
    	updateEmailDisplay();
    	updateMetricsDisplay();
    	updateRecipientDisplay();
    	
    }

    /**
	 * It checks if we want to change settings.
	 * @return
	 */
    private boolean isChangeSettingsAction() {
    	
    	return getIntent().hasExtra(SettingsMode.CHANGE_SETTINGS.name());
    	
    }
    
    /**
     * It binds all input fields.
     */
    private void bindInputs() {

        nameInput = (EditText) findViewById(R.id.settings_name_input_id);
        emailInput = (EditText) findViewById(R.id.settings_email_input_id);
        confirmButton = (Button) findViewById(R.id.confirm_setup);
        recipientButton = (Button) findViewById(R.id.pickUpRecipient);
        recipientDisplay = (TextSwitcher) findViewById(R.id.recipient_display);
        metricButton = (ToggleButton) findViewById(R.id.metric_button);

    }
    
	/**
	 * It configures main layout, this means all layouts involved in this activity.
	 */
	private void configureMainLayout() {
		
		setContentView(R.layout.set_up);
		bindInputs();
		configureRecipientDisplay();
        configureRecipientButton();
        configureConfirmButton();

	}

	/**
     * It configures recipient display. This is a text switcher which will 
     * show selected recipient email as text.
     */
    private void configureRecipientDisplay() {
    	
    	recipientDisplay.setFactory(new DefaultTextSwitcherFactory(R.style.InsideRowSmallTextStyle));
    	Animation in = AnimationUtils.loadAnimation(this,
                android.R.anim.slide_in_left);
        Animation out = AnimationUtils.loadAnimation(this,
                android.R.anim.slide_out_right);
        recipientDisplay.setInAnimation(in);
        recipientDisplay.setOutAnimation(out);
		
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.select_contact_dialog_title);
		builder.setItems(R.array.dialog_contact_options, 
			new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
			
				switch (which) {
				case 0:
					// Myself contact
					handleMyselfContact();
					break;
				case 1:
					// Choose an existing contact
					handleChooseContact();
					break;
				case 2:
					// Create a new contact
					handleNewContact();
					break;
				}
				
			}
		});
		
		recipientDialog = builder.create();
        
    }
    
	/**
     * It configures confirm button. It sets corresponding click listener.
     */
    private void configureConfirmButton() {
    	
    	final Activity activity = this;
    	confirmButton.setOnClickListener(new OnClickListener() {

        	/**
        	 * Implementation of onClick method, it performs input validations 
        	 * and calls service to save preferences into disk. 
        	 */
    		@Override
    		public void onClick(View v) {

    			// update user preferences values. Please note recipient email is always up to date
    			userPreferences.setName(nameInput.getText().toString());
    			userPreferences.setEmail(emailInput.getText().toString());
    			userPreferences.setMetricOption(metricButton.isChecked() ? Metric.KG : Metric.LB);
    			
    			if (performValidation()) {

    				// all validations passed
    				userInfoService.saveOrUpdateUserInfo(userPreferences);
    				ValidationUtil.acceptValidationForView(R.string.settings_saved);
    				
    				if (Intent.ACTION_MAIN.equals(activity.getIntent().getAction()))
    					forwardToListActivity(true);
    				else {

    					// not first time, then finish activity so to get back to previous state from the back stack
    					setResult(RESULT_OK);
    					finish();

    				}

    			}
    			
    		}
        });
    
    }

    /**
     * It configures recipient button. It sets corresponding click listener.
     */
    private void configureRecipientButton() {

		recipientButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
			
				showDialog(RECIPIENT_DIALOG_ID);
				
			}
		});

	}

    /**
     * It updates metric display. It checks corresponding toggle button state given the input.
     */
    private void updateMetricsDisplay() {
    
    	metricButton.setChecked(!Metric.LB.equals(userPreferences.getMetricOption()));
    	
    }
    
    /**
     * It updates name display with respective name.
     */
    private void updateNameDisplay() {
    	
    	nameInput.setText(userPreferences.getName());
    	
    }
    
    /**
     * It updates email display with respective email.
     */
    private void updateEmailDisplay() {
    	
    	emailInput.setText(userPreferences.getEmail());
    	
    }

    /**
     * It updates recipient display. It sets text switcher text with recipient email.
     */
    private void updateRecipientDisplay() {
    
    	String email = userPreferences.getRecipientEmail();
    	if (!ValidationUtil.isValidStringInput(email))
    		email = fetchValueFor(R.string.choose_recipient).toString();
    	
    	recipientDisplay.setText(email);
    	
    }
    
	/**
	 * When Myself has been chosen it updates default email recipient with user's email.
	 */
    private void handleMyselfContact() {
	
    	userPreferences.setRecipientEmail(emailInput.getText().toString());
		updateRecipientDisplay();
		
	}

	/**
	 * When New contact has been chosen it starts new contact activity from Contacts app.
	 */
    private void handleNewContact() {
		
		Intent intent = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
		startActivityForResult(intent, ACTIVITY_CREATE);
		
	}

	/**
	 * When Choose contact has been chosen it starts choose contact activity from Contacts app.
	 */
	private void handleChooseContact() {
		
		Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
		startActivityForResult(intent, ACTIVITY_CHOOSE);
		
	}

	/**
     * It forwards current flow to list activity.
     */
    private void forwardToListActivity(boolean backable) {
    	
    	Intent intent = new Intent(this, ViewWeightListActivity.class);
    	
    	if (!backable) {

        	// Note : this is done so there is no way to get back to this activity. It is done by business requirement.
    		// Note : in version 3.0 both flags have to be set. Version 2.1 does not contain such flag.
        	// intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        	intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    	}
    	
    	startActivity(intent);
    	finish();
    	
    }

    /**
     * It performs input validations. This is done through <code>ValidationUtil</code> utility class.
     * @return true if no errors
     */
    private boolean performValidation() {
    	
    	if (!ValidationUtil.isValidStringInput(userPreferences.getName())) {
    		
    		ValidationUtil.rejectValidationForView(nameInput, R.string.name_error);
    		return false;
    		
    	} else if (!ValidationUtil.isValidEmailInput(userPreferences.getEmail())) {
    		
    		ValidationUtil.rejectValidationForView(emailInput, R.string.email_error);
    		return false;
    		
    	} else if (!ValidationUtil.isValidEmailInput(userPreferences.getRecipientEmail())) {
    		
    		ValidationUtil.rejectValidationForView(recipientDisplay, R.string.recipient_email_error);
    		return false;
    		
    	}
    	
    	return true;
    	
    }
    
    /**
     * It displays first time access dialog. It only contains a simple welcome message with a close button.
     */
    private void displayFirstTimeDialog() {
    	
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(fetchValueFor(R.string.welcome_title));
		builder.setMessage(fetchValueFor(R.string.welcome_message));
		builder.setPositiveButton(R.string.ready, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				
				// Dismiss dialog
				
			}
		});
		builder.create().show();
    	
    }

}